function dump(object){
	var r="";
	for(var i in object)r=r+"\n"+i+": "+object[i];
	return r;
	}
function arrayContains(it,ary){
	var exists;
	exists=false;
	for(var i=0;i<ary.length; i++) {
		if(ary[i]==it){
			exists=true;
			break;
			}						
		}
	return exists;
	}
function removeFromArray(it,ary){
	for(var i=0;i<ary.length; i++) {
		if(ary[i]==it){
			ary.splice(i,1);
			break;
			}
		}
	}


	









function SolidRectangle(){
	this._width=new Amount().value(32);
	this._height=new Amount().value(32);
	this._x=new Amount().value(0);
	this._y=new Amount().value(0);
	this._fill=new It().value("#ff0000");
	this.render=function(context){
		this.realRender(context);
		};
	this.realRender=function(context){
		context.fillStyle=this._fill.value();
		context.fillRect(this._x.value(),this._y.value(),this._width.value(),this._height.value());
		};
	this.width=function(n){
		if(n==undefined)return this._width;
		if(n instanceof Amount){
			this._width.bind(n);
			return this;
			}
		this._width.value(n);
		return this;
		};
	this.height=function(n){
		if(n==undefined)return this._height;
		if(n instanceof Amount){
			this._height.bind(n);
			return this;
			}
		this._height.value(n);
		return this;
		};
	this.x=function(n){
		if(n==undefined)return this._x;
		if(n instanceof Amount){
			this._x.bind(n);
			return this;
			}
		this._x.value(n);
		return this;
		};
	this.y=function(n){
		if(n==undefined)return this._y;
		if(n instanceof Amount){
			this._y.bind(n);
			return this;
			}
		this._y.value(n);
		return this;
		};
	this.fill=function(n){
		if(n==undefined)return this._fill;
		if(n instanceof It){
			this._fill.bind(n);
			return this;
			}
		this._fill.value(n);
		return this;
		};
	}
SolidRectangle.prototype=new Layer();	
function ColorPoint(){
	this._color=new Text().value("#ff0000");
	this._distance=new Amount().value(0);
	this.color=function(it){if(it==undefined)return this._color;
							if(it instanceof Text){this._color.bind(it);return this;}
							this._color.value(it);return this;};
	this.distance=function(it){if(it==undefined)return this._distance;
							if(it instanceof Amount){this._distance.bind(it);return this;}
							this._distance.value(it);return this;};
	}	

function LinearGradientRectangle(){
	this._fill=new It().value("#ff00ff");
	this._points=[];
	this._distanceX=new Amount().value(1);
	this._distanceY=new Amount().value(1);
	this.render=function(context){
		this.refreshFill(context);
		this.realRender(context);
		};
	this.refreshFill=function(context){
		var g=context.createLinearGradient(
			this._x.value()
			,this._y.value()
			,this._x.value()+this._width.value()*this._distanceX.value()
			,this._y.value()+this._height.value()*this._distanceY.value()
			);
		for(var i=0;i<this._points.length;i++){
			var p=this._points[i];
			g.addColorStop(p.distance().value(),p.color().value());
			}
		this.fill(g);
		};
	this.point=function(it){
		this._points.push(it);
		return this;
		};
	this.distanceX=function(it){if(it==undefined)return this._distanceX;
							if(it instanceof Amount){this._distanceX.bind(it);return this;}
							this._distanceX.value(it);return this;};
	this.distanceY=function(it){if(it==undefined)return this._distance;
							if(it instanceof Amount){this._distanceY.bind(it);return this;}
							this._distanceY.value(it);return this;};
	}
LinearGradientRectangle.prototype=new SolidRectangle();	
function Picture(){
	this._width=new Amount().value(0);
	this._height=new Amount().value(0);
	this._x=new Amount().value(0);
	this._y=new Amount().value(0);
	this._image=undefined;
	this.attach=function(htmlID){
		this._image=document.getElementById(htmlID);	
		return this;
		};
	this.render=function(context){
		if(this._width.value()>0 && this._height.value()>0){
			context.drawImage(this._image
				,this._x.value()
				,this._y.value()
				,this._width.value()
				,this._height.value()
				);
			}
		else{
			context.drawImage(this._image
				,this._x.value()
				,this._y.value()
				);
			}
		};
	this.width=function(n){
		if(n==undefined)return this._width;
		if(n instanceof Amount){
			this._width.bind(n);
			return this;
			}
		this._width.value(n);
		return this;
		};
	this.height=function(n){
		if(n==undefined)return this._height;
		if(n instanceof Amount){
			this._height.bind(n);
			return this;
			}
		this._height.value(n);
		return this;
		};
	this.x=function(n){
		if(n==undefined)return this._x;
		if(n instanceof Amount){
			this._x.bind(n);
			return this;
			}
		this._x.value(n);
		return this;
		};
	this.y=function(n){
		if(n==undefined)return this._y;
		if(n instanceof Amount){
			this._y.bind(n);
			return this;
			}
		this._y.value(n);
		return this;
		};
	}	
Picture.prototype=new Layer();	
function Glyph(){
	this._x=new Amount().value(0);
	this._y=new Amount().value(0);
	this._fill=new It().value("#ff0000");
	this._font=new It().value("");//"Bold Italic 17px Serif");
	this._text=new Text().value("");
	this.render=function(context){
		context.fillStyle=this._fill.value();
		context.textBaseline="top";
		context.font=this._font.value();
		context.fillText(this._text.value(),this._x.value(),this._y.value());
		};
	this.x=function(n){
		if(n==undefined)return this._x;
		if(n instanceof Amount){
			this._x.bind(n);
			return this;
			}
		this._x.value(n);
		return this;
		};
	this.y=function(n){
		if(n==undefined)return this._y;
		if(n instanceof Amount){
			this._y.bind(n);
			return this;
			}
		this._y.value(n);
		return this;
		};
	this.fill=function(n){
		if(n==undefined)return this._fill;
		if(n instanceof It){
			this._fill.bind(n);
			return this;
			}
		this._fill.value(n);
		return this;
		};
	this.font=function(n){
		if(n==undefined)return this._font;
		if(n instanceof It){
			this._font.bind(n);
			return this;
			}
		this._font.value(n);
		return this;
		};
	this.text=function(n){
		if(n==undefined)return this._text;
		if(n instanceof Text){
			this._text.bind(n);
			return this;
			}
		this._text.value(n);
		return this;
		};
	}	
Glyph.prototype=new Layer();		
function Canvas(){
	var me=this;
	this._delay=999;
	this.globalRenderRef;
	this.ticker=0;
	this.ref=undefined;
	this.context2D=undefined;
	this.mousePressed=new Toggle().value(false);
	this.clickX=new Amount().value(0);
	this.clickY=new Amount().value(0);
	this.overX=new Amount().value(0);
	this.overY=new Amount().value(0);
	this.downX=new Amount().value(0);
	this.downY=new Amount().value(0);
	this.shiftX=new Amount().value(0);
	this.shiftY=new Amount().value(0);
	this.watchShift=false;
	this.watchX=0;
	this.watchY=0;
	this.layer=new Layer();
	this.lock=false;
	this.child=function(r){
		r.canvas.value(this);	
		this.layer.child(r);
		return this;
		};
	this.attach=function(htmlID){
		this.ref=document.getElementById(htmlID);
		this.context2D=this.ref.getContext('2d');
		this.ref.onclick=function(e){
			me.watchShift=false;
			me.clickX.value(e.pageX-me.ref.offsetLeft);
			me.clickY.value(e.pageY-me.ref.offsetTop);
			me.mousePressed.value(false);
			};
		this.ref.onmousemove=function(e){
			me.overX.value(e.pageX-me.ref.offsetLeft);
			me.overY.value(e.pageY-me.ref.offsetTop);
			if(me.watchShift){
				me.shiftX.value(me.watchX+me.overX.value()-me.downX.value());
				me.shiftY.value(me.watchY+me.overY.value()-me.downY.value());
				}
			};
		this.ref.onmousedown=function(e){
			me.downX.value(e.pageX-me.ref.offsetLeft);
			me.downY.value(e.pageY-me.ref.offsetTop);
			me.watchX=me.shiftX.value();
			me.watchY=me.shiftY.value();
			me.mousePressed.value(true);
			me.watchShift=true;
			};
		this.globalRenderRef="canvas"+Math.round(Math.random()*1000000000);
		window[this.globalRenderRef]=this;
		this.render();
		return this;
		};
	this.render=function(){
		if(this.lock)return;
		this.lock=true;
		this.ticker++;
		var canvasWidth=this.ref.width;
		var canvasHeight=this.ref.height;
		this.context2D.clearRect(0,0,canvasWidth,canvasHeight);
		this.layer.render(this.context2D);
		this.lock=false;
		};
	this.delay=function(v){
		this._delay=v;
		return this;
		}
	this.startRenderLoop=function(){
		this.render();
		if(this._delay>0)setTimeout("window['"+this.globalRenderRef+"'].startRenderLoop()",this._delay);
		};
	}	
function POV(){
	this.camera=new XYZ(0,0,300);//the 3D position of a point representing the camera 
	this.ray=new XYZ(1*Math.PI,0*Math.PI,0*Math.PI);//the orientation of the camera (represented, for instance, by Tait-Bryan angles)
	this.viewer=new XYZ(0,0,600);//the viewer's position relative to the display surface 
	this.xy=function(point){
		var d=new XYZ(0,0,0);//the 2D projection of 'a'
		var b=new XY(0,0);//result
		d.x=Math.cos(this.ray.y)
			*(Math.sin(this.ray.z)*(point.y-this.camera.y)+Math.cos(this.ray.z)*(point.x-this.camera.x))
			 -Math.sin(this.ray.y)*(point.z-this.camera.z);
		d.y=Math.sin(this.ray.x)
			*(Math.cos(this.ray.y)*(point.z-this.camera.z)+Math.sin(this.ray.y)*(Math.sin(this.ray.z)*(point.y-this.camera.y)+Math.cos(this.ray.z)*(point.x-this.camera.x)))
			 +Math.cos(this.ray.x)*(Math.cos(this.ray.z)*(point.y-this.camera.y)-Math.sin(this.ray.z)*(point.x-this.camera.x));
		d.z=Math.cos(this.ray.x)
			*(Math.cos(this.ray.y)*(point.z-this.camera.z)+Math.sin(this.ray.y)*(Math.sin(this.ray.z)*(point.y-this.camera.y)+Math.cos(this.ray.z)*(point.x-this.camera.x)))
			 -Math.sin(this.ray.x)*(Math.cos(this.ray.z)*(point.y-this.camera.y)-Math.sin(this.ray.z)*(point.x-this.camera.x));
		b.x=(d.x-this.viewer.x)*(this.viewer.z/d.z);
		b.y=(d.y-this.viewer.y)*(this.viewer.z/d.z);
		return b;
		};
	this.camera=function(n){
		if(n==undefined)return this._camera;
		if(n instanceof It){
			this._camera.bind(n);
			return this;
			}
		this._camera.value(n);
		return this;
		};
	}
				